﻿using EventMgrLib;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace demo.流程图控件
{
    public class Canvas : Panel
    {
        /// <summary>
        /// 流程
        /// </summary>
        public Flow EditFLow { get; private set; }
        /// <summary>
        /// 存储工具
        /// </summary>
        private readonly ToolMgr _toolMgr;
        /// <summary>
        /// 事件聚合器
        /// </summary>
        private EventMgr _em;
        /// <summary>
        /// 用于定位到位置的控件
        /// </summary>
        public ComboBox comboBox;
        #region Constructor

        public Canvas()
        {
            _toolMgr = ToolMgr.Ins;
            _em = EventMgr.Ins;
            SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();
            AllowDrop = true;
            Tools = new MyList<ActionItem>();//注意自定义控件集合不能加get和set属性，使用时会报错
            Connections = new List<Connection>();//注意自定义控件集合不能加get和set属性，使用时会报错
            _rnd = new Random();
            _proxy = new Proxy(this);
            _hook = new GlobalHook();
            _hook.KeyDown += hook_KeyDown;
            //bool b = _hook.Start();

            Tools.ItemAdded += Tools_ItemAdded;//注册MyList添加移除所触发的事件
            Tools.ItemRemove += Tools_ItemRemove;//注册MyList添加移除所触发的事件

            

        }

        #region MyList添加移除所触发的事件

        private void Tools_ItemRemove(ActionItem obj)
        {
            comboBox.Items.Remove(obj);
            
        }

        private void Tools_ItemAdded(ActionItem obj)
        {
           
            comboBox.Items.Add(obj);
            
        }

        #endregion

        #endregion Constructor

        #region 字段

        private bool _leftMouse;

        /// <summary>
        /// 用于计算鼠标移动距离
        /// </summary>
        private DiagramPoint _stratPoint = new DiagramPoint();

        /// <summary>
        /// 追踪鼠标画连接线
        /// </summary>
        private bool _tracking;

        /// <summary>
        /// 全局钩子
        /// </summary>
        private GlobalHook _hook;
        private readonly Size _gridSize = new Size(10, 10);
        /// <summary>
        /// 代理类
        /// </summary>
        private readonly Proxy _proxy;
        /// <summary>
        /// 选择的实体
        /// </summary>
        public Entity _selectedEntity;
        /// <summary>
        /// 悬停实体
        /// </summary>
        private Entity _hoveredEntity;
        private readonly Random _rnd;
        

        #endregion 字段

        #region 属性

        public string FileName { get; set; } = string.Empty;

        /// <summary>
        /// 是否显示点网格
        /// </summary>
        [Description("是否显示点网格"), Category("Layout"), DefaultValue(true)]
        public bool ShowGrid
        {
            get { return _showGrid; }
            set { _showGrid = value; Invalidate(true); }
        }
        private bool _showGrid = true;
        /// <summary>
        /// 连线默认颜色
        /// </summary>
        [Browsable(true), Description("连线默认颜色"), Category("Layout")]
        public Color LineColor { get; set; } = Color.Silver;
        /// <summary>
        /// 连线选中颜色
        /// </summary>
        [Browsable(true), Description("连线选中颜色"), Category("Layout")]
        public Color LineSelectedColor { get; set; } = Color.Green;
        /// <summary>
        /// 连线悬停颜色
        /// </summary>
        [Browsable(true), Description("连线悬停颜色"), Category("Layout")]
        public Color LineHoveredColor { get; set; } = Color.Blue;
        /// <summary>
        /// 视觉原点，左上角坐标
        /// </summary>
        [Browsable(true), Description("视觉原点，左上角坐标"), Category("Layout")]
        public DiagramPoint ViewOriginPoint { get; set; } = new DiagramPoint(0, 0);
        /// <summary>
        /// 工具集合
        /// </summary>
        [Browsable(false)]
        public MyList<ActionItem> Tools;
        /// <summary>
        /// 连接边类，记录实体连接边状态信息
        /// </summary>
        [Browsable(false)]
        public List<Connection> Connections;

        #endregion 属性

        #region 鼠标事件

        /// <summary>
        /// 拖动进入,设置鼠标复制效果
        /// </summary>
        /// <param name="e"></param>
        protected override void OnDragEnter(DragEventArgs e)
        {
            base.OnDragEnter(e);
            if (e.Data.GetDataPresent(typeof(TreeNode)))
            {
                e.Effect = DragDropEffects.Copy;
            }
        }

        /// <summary>
        /// 拖放
        /// </summary>
        /// <param name="e"></param>
        protected override void OnDragDrop(DragEventArgs e)
        {
            base.OnDragDrop(e);

            if (e.Effect == DragDropEffects.Copy)
            {
                TreeNode node;
                if (e.Data.GetDataPresent(typeof(TreeNode)))
                {
                    node = (TreeNode)(e.Data.GetData(typeof(TreeNode)));
                }
                else
                {
                    return;
                }

                string toolNmae = node.Text;
                ActionItem dragTool = _toolMgr.Tools.Find(t => t.ItemName == toolNmae);
                if (dragTool == null) return;               
                ActionItem newItem = dragTool.CopyFromTool();
                AddTool(newItem);
                EditFLow.ActionItems.Add(newItem);//需要优化，没有实现数据绑定
                newItem.Text = newItem.ItemName;
                Point p1 = MousePosition;
                Point p2 = PointToScreen(new Point(0, 0));
                newItem.X = p1.X - p2.X - ViewOriginPoint.GetPoint().X;
                newItem.Y = p1.Y - p2.Y - ViewOriginPoint.GetPoint().Y;
                newItem.Index = 10;
                #region  此段代码用于跳转到坐标位置
                newItem.ViewOriginPoint.X =ViewOriginPoint.GetPoint().X;
                newItem.ViewOriginPoint.Y = ViewOriginPoint.GetPoint().Y;
                #endregion
            }
        }
        /// <summary>
        /// 鼠标落下
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            _leftMouse = e.Button == MouseButtons.Left;
            _stratPoint = e.Location;//记录鼠标坐标

            int entityTYpe = -1;
            Entity hoverEdentity = Tools.FirstOrDefault(f => f.Hit(e.Location));//根据鼠标坐标确定是否点击到工具实体 f.hit方法里有判断是否在工具矩形内

            //情况1,连线，未点击到实体同时选择的实体是工具
            if (hoverEdentity == null && _selectedEntity is ActionItem tool)
            {
                //工具里有节点属性 所以分支条件可以使用选择实体是否是工具
                Connector 连接点 = tool.HitConnector(e.Location);//节点的连接点被点击，创建一个尚未成功的连接 
                if (连接点 != null)
                {
                    Point point = e.Location;
                    point.Offset(-ViewOriginPoint.GetPoint().X, -ViewOriginPoint.GetPoint().Y);
                    Connection 连接 = AddConnection(连接点.Point, point);//拖拽创建连接
                    连接.From.OwnerEntity = 连接点.OwnerEntity;
                    连接.From.ConnectorsIndexOfContainEntity = 连接点.ConnectorsIndexOfContainEntity;
                    连接.FromID = 连接点.OwnerEntity.ObjectId;
                    连接.FromIndex = 连接点.ConnectorsIndexOfContainEntity;
                    UpdateSelected(连接.To);//将当前选中的实体设置为刚创建的连接的To连接点
                    连接点.AttachConnector(连接.From);//Tool的连接点 连接Connection.Form
                    _tracking = true;
                    Invalidate(true);
                    Console.WriteLine("情况1,连线");
                    return;
                }
            }
            //点击的实体不为空，改变选择的对象实体
            if (hoverEdentity != null)
            {
                //情况2,移动节点
                Console.WriteLine("情况2,移动节点");
                _tracking = true;
                //选择的对象实体改变
                OnSelectChanged(hoverEdentity, new SelectElementChangedEventArgs { CurrentEntity = hoverEdentity, PreviousEntity = _selectedEntity });
            }
            else//主要用于连接线实体判断动作
            {
                //移动画布，添加连接时加入现在从连接边类找到符合的三类实体
                hoverEdentity = Connections.FirstOrDefault(f =>
                {
                    if (f.Hit(e.Location))
                    {
                        entityTYpe = 2;
                        return true;
                    }
                    if (f.From.Hit(e.Location))
                    {
                        entityTYpe = 3;
                        return true;
                    }
                    if (f.To.Hit(e.Location))
                    {
                        entityTYpe = 4;
                        return true;
                    }
                    return false;
                });

                if (entityTYpe == 3)
                {
                    hoverEdentity = ((Connection)hoverEdentity)?.From;//情况3，移动连接线起点
                    Console.WriteLine("情况3,移动连接线起点");
                    _tracking = true;
                }
                else if (entityTYpe == 4)
                {
                    hoverEdentity = ((Connection)hoverEdentity)?.To;//情况4，移动连接线终点
                    Console.WriteLine("情况4，移动连接线终点");
                    _tracking = true;
                }
                else if (entityTYpe == 2)
                {
                    //情况5，点击连接线拖动整个画布
                    Console.WriteLine("情况5，点击连接线拖动整个画布");
                    OnSelectChanged(hoverEdentity, new SelectElementChangedEventArgs { CurrentEntity = hoverEdentity, PreviousEntity = _selectedEntity });
                }
                else
                {
                    //情况6，移动画布
                    Console.WriteLine("情况6，移动画布");
                }
            }
            //主要移动画布情况
            if (hoverEdentity == null)
            {
                OnSelectChanged(_proxy, new SelectElementChangedEventArgs { CurrentEntity = hoverEdentity, PreviousEntity = _selectedEntity });
            }
            UpdateSelected(hoverEdentity);
            Invalidate(true);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (_tracking)
            {
                //移动实体
                _selectedEntity.Move(new Point(e.X - _stratPoint.GetPoint().X, e.Y - _stratPoint.GetPoint().Y));
                //移动点
                if (_selectedEntity is Connector)
                {
                    for (int k = 0; k < Tools.Count; k++)
                    {
                        Tools[k].HitConnector(e.Location);
                    }
                }
            }
            else if (_leftMouse)
            {
                //移动画布
                ViewOriginPoint = new DiagramPoint(ViewOriginPoint.GetPoint().X + e.X - _stratPoint.GetPoint().X, ViewOriginPoint.GetPoint().Y + e.Y - _stratPoint.GetPoint().Y);
                Save();
            }

            int entityTYpe = -1;//0:ShapeBase;1:ShapeBase.connectors;2:connections;3:connections.From;4:connections.To.
            Entity hoverEdentity = Tools.Cast<Entity>().FirstOrDefault(f => f.Hit(e.Location));
            if (hoverEdentity == null)
            {
                hoverEdentity = Connections.FirstOrDefault(f =>
                {
                    if (f.Hit(e.Location))
                    {
                        entityTYpe = 2;
                        return true;
                    }
                    if (f.From.Hit(e.Location))
                    {
                        entityTYpe = 3;
                        return true;
                    }
                    if (f.To.Hit(e.Location))
                    {
                        entityTYpe = 4;
                        return true;
                    }
                    return false;
                });
            }

            if (entityTYpe == 3)
                hoverEdentity = ((Connection)hoverEdentity)?.From;
            if (entityTYpe == 4)
                hoverEdentity = ((Connection)hoverEdentity)?.To;

            UpdateHovered(hoverEdentity);

            _stratPoint = e.Location;
            Invalidate(true);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            _leftMouse = false;

            if (!_tracking) return;
            Point p = new Point(e.X, e.Y);

            if (_selectedEntity is Connector 箭头)
            {
                for (int k = 0; k < Tools.Count; k++)
                {
                    Connector tool连接点;
                    if ((tool连接点 = Tools[k].HitConnector(p)) == null) continue;
                    //鼠标释放的地方有节点的Connector，成功建立一个连接
                    tool连接点.AttachConnector(箭头);//Tool的连接点 连接Connection.To
                    if (箭头.OwnerEntity is Connection connection)
                    {
                        connection.ToID = tool连接点.OwnerID;
                        connection.ToIndex = tool连接点.ConnectorsIndexOfContainEntity;
                    }
                    箭头.OwnerEntity = tool连接点.OwnerEntity;

                    箭头.ConnectorsIndexOfContainEntity = tool连接点.ConnectorsIndexOfContainEntity;
                    箭头.ConnectorDirection = (ConnectorDirection)箭头.ConnectorsIndexOfContainEntity;
                    tool连接点.Hovered = false;
                    _tracking = false;
                    Save();
                    return; //成功建立连接，退出
                }

                //没有成功建立连接，删掉没成功的连接
                箭头.Release();
                DeleteElement(箭头.OwnerEntity);
            }
            _tracking = false;
        }
        /// <summary>
        /// 鼠标双击
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            //找到功能块
            var tool = Tools.FirstOrDefault(f => f.Hit(e.Location));
            //找到连接线
            var connect= Connections.FirstOrDefault(f=>f.Hit(e.Location));
            if (tool != null)
                OnIncomingParameter(null, new IncomingParametersEventArgs { actionItem = tool });
            
                



        }

        #endregion 鼠标事件

        #region Print

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);
            Graphics g = e.Graphics;

            if (_showGrid)
                ControlPaint.DrawGrid(g, ClientRectangle, _gridSize, BackColor);
        }

        /// <summary>
        /// 绘制
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);//解决闪烁

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            for (int k = 0; k < Connections.Count; k++)
            {
                Connections[k].Paint(g);
                //Connections[k].From.Paint(g);
                //Connections[k].To.Paint(g);
            }

            for (int k = 0; k < Tools.Count; k++)
            {
                Tools[k].Paint(g);
            }

            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);//解决闪烁
        }

        #endregion Print

        #region 公有方法

        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="flow"></param>
        /// <returns></returns>
        public bool Import(Flow flow)
        {
            EditFLow = flow;

            Tools.Clear();
            foreach (var tool in EditFLow.ActionItems)
            {
                AddTool(tool);
            }

            Connections.Clear();
            foreach (var connection in EditFLow.Connections)
            {
                ActionItem @from = null;
                ActionItem to = null;
                foreach (ActionItem shape in Tools)
                {
                    if (connection.FromID == shape.ObjectId)
                    {
                        @from = shape;
                    }

                    if (connection.ToID == shape.ObjectId)
                    {
                        to = shape;
                    }

                    if (@from != null && to != null)
                    {
                        break;
                    }
                }

                if (@from == null || to == null)
                {
                    return false;
                }

                var conn = LoadConnection(@from.Connectors[connection.FromIndex], to.Connectors[connection.ToIndex]);
                conn.ObjectId = connection.ObjectId;
                conn.InitialPath();
            }
            LoadParamsToCanvas();
            Invalidate(true);
            return true;
        }

        public void Save()
        {
            if (EditFLow != null)
            {
                EditFLow.ViewOriginPoint = ViewOriginPoint.GetPoint();
                //foreach (var connection in Connections)
                //{
                //    if (EditFLow.Connections.Contains())
                //    {
                //    }
                //}
            }
        }

        public void Clear()
        {
            Tools.Clear();
            Connections.Clear();
        }

        public void Stop()
        {
            _hook.Stop();
        }

        public void GetFocus()
        {
            _hook.Start();
        }

        public void LostFocus()
        {
            _hook.Stop();
        }

        //导入文件

        #endregion 公有方法

        #region 私有方法

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == Keys.Delete)
            {
                DeleteSelectElement();
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        /// <summary>
        /// 按键钩子
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void hook_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                DeleteSelectElement();
            }
        }

        /// <summary>
        /// 删除中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnDeleting(object sender, DeletingEventArgs e)
        {
            OnElementDeleting?.Invoke(sender, e);
        }

        /// <summary>
        /// 删除后
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnDeleted(object sender, EventArgs e)
        {
            OnElementDeleted?.Invoke(sender, e);
        }

        /// <summary>
        /// 选择对象切换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnSelectChanged(object sender, SelectElementChangedEventArgs e)
        {
            OnSelectElementChanged?.Invoke(sender, e);
        }

        /// <summary>
        /// 刷新改变后的UI
        /// </summary>
        /// <param name="entity"></param>
        private void UpdateSelected(Entity entity)
        {
            if (_selectedEntity != null)
            {
                _selectedEntity.IsSelected = false;
                _selectedEntity.Invalidate();
                _selectedEntity = null;
            }

            if (entity != null)
            {
                _selectedEntity = entity;
                entity.IsSelected = true;
                if (entity is ActionItem tool)
                {
                    _em.GetEvent<SelectActionChanged>().Publish(tool);
                }

                entity.Invalidate();
            }
        }

        /// <summary>
        /// 更新悬浮
        /// </summary>
        /// <param name="entity"></param>
        private void UpdateHovered(Entity entity = null)
        {
            if (_hoveredEntity != null)
            {
                _hoveredEntity.Hovered = false;
                _hoveredEntity.Invalidate();
                _hoveredEntity = null;
            }

            if (entity != null)
            {
                entity.Hovered = true;
                _hoveredEntity = entity;
                _hoveredEntity.Invalidate();
            }
        }

        private ActionItem AddTool(ActionItem tool)
        {
            tool.InitCanvas(this);
            Tools.Add(tool);
            tool.Site = this;
            Invalidate(true);
            return tool;
        }

        /// <summary>
        /// 添加连接
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="addToFlow"></param>
        /// <returns></returns>
        private Connection AddConnection(DiagramPoint from, DiagramPoint to, bool addToFlow = true)
        {
            Connection con = new Connection(@from, to);//创建连接
            con.Site = this;
            con.From.Site = this;

            con.To.Site = this;
            Connections.Add(con);
            if (addToFlow)
            {
                EditFLow.Connections.Add(con);
            }

            Invalidate(true);
            return con;
        }

        private Connection LoadConnection(Connector from, Connector to)
        {
            Connection con = AddConnection(@from.Point, to.Point, false);
            con.From.OwnerEntity = @from.OwnerEntity;
            con.From.ConnectorsIndexOfContainEntity = @from.ConnectorsIndexOfContainEntity;
            con.To.OwnerEntity = to.OwnerEntity;
            con.To.ConnectorsIndexOfContainEntity = to.ConnectorsIndexOfContainEntity;
            con.Site = this;
            @from.AttachConnector(con.From);
            to.AttachConnector(con.To);

            return con;
        }
        /// <summary>
        /// 删除选择的成分
        /// </summary>
        private void DeleteSelectElement()
        {
            DeleteElement(_selectedEntity);
        }
        /// <summary>
        /// 加载参数到流程图控件里
        /// </summary>
        private void LoadParamsToCanvas()
        {
            ViewOriginPoint = EditFLow.ViewOriginPoint;
            LineHoveredColor = EditFLow.LineHoveredColor;
            LineSelectedColor = EditFLow.LineSelectedColor;
            LineColor = EditFLow.LineColor;
            BackColor = EditFLow.BackColor;
            ShowGrid = EditFLow.ShowGrid;
        }

        private void DeleteElement(Entity entity)
        {
            if (entity == null) return;

            if (entity is ActionItem tool)
            {
                //1.声明事件  2.调用
                DeletingEventArgs deletingEventArgs = new DeletingEventArgs();
                OnDeleting(entity, deletingEventArgs);

                if (!deletingEventArgs.Cancel)
                {
                    Tools.Remove(tool);
                    EditFLow.ActionItems.Remove(tool);
                    Invalidate(true);
                    OnDeleted(entity, EventArgs.Empty);
                }
            }
            else if (entity is Connection connection)
            {
                DeletingEventArgs deletingEventArgs = new DeletingEventArgs();
                OnDeleting(entity, deletingEventArgs);

                if (!deletingEventArgs.Cancel)
                {
                    int n = -1;

                    for (int i = 0; i < EditFLow.Connections.Count; i++)
                    {
                        if (EditFLow.Connections[i].ObjectId == connection.ObjectId)
                        {
                            n = i;
                            break;
                        }
                    }

                    if (n > -1)
                    {
                        EditFLow.Connections.RemoveAt(n);
                    }
                    Connections.Remove(connection);

                    Invalidate(true);
                    OnDeleted(entity, EventArgs.Empty);
                }
            }
        }

        #endregion 私有方法

        #region 事件委托

        public event EventHandler<DeletingEventArgs> OnElementDeleting;

        public event EventHandler<EventArgs> OnElementDeleted;

        public event EventHandler<SelectElementChangedEventArgs> OnSelectElementChanged;

        /// <summary>
        /// 自定义事件，用于传出工具
        /// </summary>
        public event EventHandler<IncomingParametersEventArgs> OnIncomingParameters;

        private void OnIncomingParameter(object sender, IncomingParametersEventArgs e)
        {
            OnIncomingParameters?.Invoke(sender, e);
        }
        

        #endregion 事件委托

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.ResumeLayout(false);
        }

        public void Delete()
        {
            DeleteSelectElement();
        }
    }

   

    /// <summary>
    /// 自定义事件参数，用于传出工具
    /// </summary>
    public class IncomingParametersEventArgs:EventArgs
    {
        public ActionItem actionItem;
    }

    
}
